////////////////////////////////////////
//	File Header
//	Author: Stephen Ringer | stephen.ringer@gmail.com
//	File: SAGAWS.h
//
////////////////////////////////////////
#pragma once
////////////////////////////////////////
//	File Includes
#include <windows.h>
#include "../SAGANetwork/SAGANetworkDevice.h"
#include "../SAGAD3D/SAGA.h"
#include "SAGAQueue.h"
//	Library Includes
#pragma comment(lib, "ws2_32.lib")
//
////////////////////////////////////////

////////////////////////////////////////
//	Helper Function
BOOL WINAPI DllEntryPoint( HINSTANCE hDll, DWORD fdwReason, LPVOID lpvRserved );
//
////////////////////////////////////////

////////////////////////////////////////
//	Forward Declarations
class SAGASocketObject;
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGACLIENT
//	Purpose:
//		for server to keep list of connected clients
typedef struct SAGACLIENT_TYPE 
{
	SOCKET skToClient;
	UINT   nID;
} SAGACLIENT;
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGASocketObject
class SAGASocketObject 
{
public:
	SAGASocketObject(FILE *pLog);
	~SAGASocketObject();

	bool    IsRunning() { return m_bRunning; }

	// socket misc operations
	HRESULT CreateSocket();
	HRESULT Bind(int nPort);
	HRESULT Listen();
	HRESULT Accept(SOCKET *skToNewClient);
	HRESULT Connect(char *chServer, int nPort);
	void    Disconnect();

	// send and receive data
	int     Send(const char*,UINT);
	int     Send(const char*,UINT,SOCKET);
	HRESULT Receive(SOCKET sk);

	void    FeedByHand(SAGAPACKAGE *pPkg);

	// for informational purposes
	SOCKET  GetSocket()			{ return m_skSocket; }
	void    LogLastWSAError(const char*);

	// information about inbox
	bool    IsPkgWaiting()		{ return (m_pInbox->GetCount() > 0); }
	UINT    GetNextPkgSize()	{ return (m_pInbox->GetFrontSize()); }
	HRESULT GetNextPkg(SAGAPACKAGE*);

private:
	SAGAQueue   *m_pInbox;
	SOCKET      m_skSocket;
	char       *m_Buffer;
	bool        m_bRunning;
	FILE       *m_pLog;

	void Log(char *chString, ...);
}; 
//
////////////////////////////////////////

////////////////////////////////////////
//	Class Name: SAGAWS
//	Purpose:
//		Class definition for a NetworkDevice object, implementing the
//		interface SAGANetworkDevice
class SAGAWS : public SAGANetworkDevice 
{
public:
	SAGAWS(HINSTANCE hDLL);
	~SAGAWS();

	// initialize the engine stuff
	HRESULT Init(HWND, SAGANETMODE, int, char*, UINT, UINT, bool);

	// Interface functions
	void    Release();
	bool    IsRunning() { return m_bRunning; }
	HRESULT MsgProc(WPARAM wp, LPARAM lp);
	HRESULT SendToServer(const SAGAPACKAGE*);
	HRESULT SendToClients(const SAGAPACKAGE*);
	HRESULT SendToClient(const SAGAPACKAGE*,UINT);
	bool    IsPkgWaiting()           { return m_pSockObj->IsPkgWaiting();   }
	UINT    GetNextPkgSize()         { return m_pSockObj->GetNextPkgSize(); }
	HRESULT GetNextPkg(SAGAPACKAGE *pPkg) { return m_pSockObj->GetNextPkg(pPkg); }

private:
	SAGASocketObject *m_pSockObj;
	SAGANETMODE       m_Mode;
	SAGACLIENT        m_Clients[256];
	char             m_ClCount;
	UINT             m_ClID;
	UINT             m_ClMax;
	char            *m_Buffer;
	FILE            *m_pLog;

	// initialize socketobjects
	HRESULT CreateServer(SAGASocketObject **ppSkObject);
	HRESULT CreateClient(SAGASocketObject **ppSkObject);

	// during message processing
	HRESULT OnAccept();
	HRESULT OnReceive(SOCKET skReceiving);
	HRESULT OnDisconnect(SOCKET skDisconnecting);

	void    Log(char *, ...);
};
//
////////////////////////////////////////